<script setup lang="ts">
import {ref, watch} from 'vue'
import {NFormItem, NInput, NSwitch} from 'naive-ui'
import {useTable} from '@/composables/useTable'
import {
  fetchUpdatePassWord,
  fetchUserList,
  fetchUserSave,
  fetchUserUpdate,
  fetchUserDetails,
  fetchUserBindRole
} from "@/api/user"
import {
  ClickType,
  DEFAULT_MENU_MODEL,
  useColumns,
  useContextMenuOptions,
  useFormRules,
} from '@/views/manager/user/mock/useUserConfig'
import {createBooleanComputedRef} from "@/utils/to"
import BaseCrudPage from '@/components/page/BaseCrudPage.vue'
import BaseFormModal from '@/components/modal/BaseFormModal.vue'
import SearchForm from "@/views/manager/user/components/SearchForm.vue";

import {fetchRoleList} from '@/api/role'
import type {Option} from "naive-ui/es/transfer/src/interface";

defineOptions({name: 'User'})

// 状态管理
const optionType = ref<ClickType>(ClickType.NONE)
const showModal = ref(false)
const showUpdatePasswordModel = ref(false)
const formValue = ref<User.BaseInfo>(DEFAULT_MENU_MODEL)
const loading = ref(false)


// 表格配置
const {
  dataRef,
  reset,
  loading: tableLoading,
  pagination,
  tableConfig,
  handlePageChange,
  refresh,
  rowKey
} = useTable<User.BaseInfo[]>({
  pageSize: 10,
  api: (params) => fetchUserList({...params}),
  immediate: true,
  minHeight: 560,
  maxHeight: 560,
})


// 处理点击事件
function handlerClick(type: ClickType, row: User.BaseInfo) {

  optionType.value = type
  if (type == ClickType.UPDATE) {
    formValue.value = {...row}
    showModal.value = true
    setRoleOptions();
    setRoleValues(row.userId)
  } else if (type == ClickType.ADD) {
    formValue.value = {...DEFAULT_MENU_MODEL}
    showModal.value = true
    setRoleOptions();
  } else if (type === ClickType.DELETE) {
    showModal.value = true
  } else if (type === ClickType.UPDATE_PASSWORD) {
    showUpdatePasswordModel.value = true
    formValue.value = {
      ...row
    }
  }

  refresh()
}


const columns = useColumns(handlerClick)
const contextMenuOptions = useContextMenuOptions(handlerClick)
const rules = useFormRules()

// 计算属性
const accountLockedBoolean = createBooleanComputedRef(formValue, 'accountLockedType', 'LOCK', 'UNLOCK')

// 处理表单提交
async function handleSubmit(model: User.BaseInfo) {
  try {
    loading.value = true
    if (optionType.value === ClickType.UPDATE) {
      await fetchUserUpdate({
        ...model
      })
      showModal.value = false
      //绑定用户
      fetchBindRole(model.userId)
    } else if (optionType.value === ClickType.ADD) {
      await fetchUserSave({
        ...model
      })
      //绑定用户
      fetchBindRole(model.userId)
      showModal.value = false
    } else if (optionType.value === ClickType.UPDATE_PASSWORD) {
      await fetchUpdatePassWord({
        userId: model.userId,
        password: model.password
      })
      showUpdatePasswordModel.value = false
    }
    roleValues.value = []
    refresh()
  } catch (error) {
    window.$message?.error('操作失败：' + error)
  } finally {
    loading.value = false
  }
}


const roleOptions = ref<Option[]>([]);
const defaultRole = ref<Option[]>([]);

//获取角色列表，并且设置相应的值
async function setRoleOptions() {
  const roleList = await fetchRoleList();
  roleOptions.value = roleList.map(node => ({
    label: node.roleName,
    value: node.roleId,
  })).filter(Boolean) as Option[]
}

//当前用户的角色
const roleValues = ref<[]>([])

//绑定用户
async function fetchBindRole(userIdParam?: number | string) {
  if (userIdParam) {
    const param = {
      userId: userIdParam,
      roleIds: roleValues.value
    }
    await fetchUserBindRole(param);
  }
}

async function setRoleValues(userId?: number | string) {
  if (userId) {
    const userResponse = await fetchUserDetails(userId)
    if (userResponse) {
      roleValues.value = userResponse.roles.map((role) => (role.roleId
      )).filter(Boolean) as [];
    }
  }
}


// 监听 menuType 的变化
watch(() => roleValues.value, (newValue: [], oldValue: []) => {
  if (roleValues.value.length == 0) {
    defaultRole.value = []
    return
  }
  const removed = oldValue.filter(item => !newValue.includes(item)) as []
  const added = newValue.filter(item => !oldValue.includes(item))
  if (added.length != 0) {
    const addedRoles = roleOptions.value.filter(role => added.includes(role.value));
    defaultRole.value.push(...addedRoles);
  }
  if (removed.length != 0) {
    defaultRole.value = defaultRole.value.filter(node => !removed.includes(node.value));
  }

})
</script>

<template>
  <BaseCrudPage
    title="角色管理"
    :loading="tableLoading"
    :data="dataRef"
    :columns="columns"
    :pagination="pagination"
    :table-config="tableConfig"
    :context-menu-options="contextMenuOptions"
    :row-key="rowKey"
    @update:page="handlePageChange"
  >
    <template #search>
      <SearchForm
        :on-search="refresh"
        :on-reset="reset"
      />
    </template>
    <template #model_other>
      <BaseFormModal
        v-model:show="showUpdatePasswordModel"
        :title="optionType === ClickType.UPDATE_PASSWORD ? '修改密码' : ''"
        :model="formValue"
        :rules="rules"
        :loading="loading"
        @submit="handleSubmit"
      >
        <n-form-item label="新密码:" path="password">
          <n-input type="password" show-password-on="click" v-model:value="formValue.password"
                   placeholder="请输入新密码"/>
        </n-form-item>
      </BaseFormModal>
    </template>
    <template #modal>
      <BaseFormModal
        v-model:show="showModal"
        :title="optionType === ClickType.UPDATE ? '修改角色' : '新增角色'"
        width="800px"
        :model="formValue"
        :rules="rules"
        :loading="loading"
        @submit="handleSubmit"
      >
        <n-form-item label="账号:" path="username" v-if="optionType==ClickType.ADD">
          <n-input v-model:value="formValue.username"
                   placeholder="请输入账号"/>
        </n-form-item>
        <n-form-item label="账号:" path="username" v-else-if="optionType==ClickType.UPDATE">
          <n-input v-model:value="formValue.username" disabled placeholder="请输入账号"/>
        </n-form-item>

        <n-form-item label="用户名称:" path="name">
          <n-input v-model:value="formValue.name" placeholder="请输入用户名称"/>
        </n-form-item>
        <n-form-item label="邮箱:" path="email">
          <n-input v-model:value="formValue.email" placeholder="请输入邮箱"/>
        </n-form-item>
        <n-form-item label="手机号:" path="phone">
          <n-input v-model:value="formValue.phone" placeholder="请输入手机号"/>
        </n-form-item>
        <n-form-item label="绑定的微信号:" path="wechat">
          <n-input v-model:value="formValue.wechat" disabled placeholder="绑定微信号"/>
        </n-form-item>
        <n-form-item label="是否锁定:" path="accountLockedType">
          <n-switch v-model:value="accountLockedBoolean"/>
        </n-form-item>
        <n-form-item label="性别:" path="userGender">
          <n-radio-group v-model:value="formValue.userGender" name="userGender">
            <n-radio-button value="MALE">
              男
            </n-radio-button>
            <n-radio-button value="FEMALE">
              女
            </n-radio-button>
          </n-radio-group>
        </n-form-item>
        <n-form-item label="是否启用:" path="enable">
          <n-switch v-model:value="formValue.enable"/>
        </n-form-item>
        <n-form-item :span="5" label="默认角色:" path="defaultRole">
          <n-cascader
            v-model:value="formValue.defaultRole"
            placeholder="选择默认角色"
            :options="defaultRole"
          />
        </n-form-item>
        <n-form-item label="用户角色:" path="roleValues">
          <n-transfer
            size="small"
            v-model:value="roleValues"
            :options="roleOptions"
            virtual-scroll
            source-title="可选角色"
            target-title="已选角色"
          />
        </n-form-item>
      </BaseFormModal>
    </template>

  </BaseCrudPage>

</template>
<style scoped>
.container {
  padding: 16px;
  background-color: #f5f7fa;
  min-height: 100%;
}

:deep(.n-data-table) {
  background-color: #fff;
  border-radius: 4px;
}

:deep(.n-card) {
  background-color: transparent;
  box-shadow: none;
}

:deep(.n-card-header) {
  padding: 0 0 16px 0;
}

:deep(.n-button:not(:last-child)) {
  margin-right: 12px;
}

:deep(.n-form-item-label) {
  font-weight: 500;
}
</style>
